package com.zshan.clinic.admin.service.notice;

import com.zshan.clinic.admin.entity.vo.ClinicNoticeVo;
import com.zshan.clinic.common.constant.CommonConstant;
import com.zshan.clinic.common.entity.BatchDTO;
import com.zshan.clinic.common.enums.NoticeTypeEnum;
import com.zshan.clinic.common.enums.YesOrNoEnum;
import com.zshan.clinic.common.exception.BusinessFailException;
import com.zshan.clinic.common.util.page.PageInfo;
import com.zshan.clinic.common.util.page.PageUtils;
import com.zshan.clinic.common.util.string.StringUtil;
import com.zshan.clinic.database.dao.ClinicNoticeLastReadMapper;
import com.zshan.clinic.database.dao.ClinicNoticeMapper;
import com.zshan.clinic.database.model.ClinicNotice;
import com.zshan.clinic.database.model.ClinicNoticeExample;
import com.zshan.clinic.database.model.ClinicNoticeLastRead;
import com.zshan.clinic.database.model.ClinicNoticeLastReadExample;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 消息通知
 * @author lichen
 */
@Service
public class ClinicNoticeService {

    @Autowired
    private ClinicNoticeMapper clinicNoticeMapper;

    @Autowired
    private ClinicNoticeLastReadMapper clinicNoticeLastReadMapper;



    /**
     * 获取消息未读数
     * @param empId
     * @return
     */
    public Integer getUnreadNum(Long clinicId,Long empId) {
        ClinicNoticeLastRead clinicNoticeLastRead = geLastReadByEmpId(clinicId,empId);
        if(clinicNoticeLastRead != null){
            return clinicNoticeLastRead.getUnreadNum();
        }
        return CommonConstant.DEFAULT_0;
    }


    /**
     * 查询消息列表
     * @param empId
     * @param pageNo
     * @param pageSize
     * @return
     */
    public PageInfo<ClinicNoticeVo> getNoticeList(Long clinicId,Long empId, Integer pageNo, Integer pageSize) {
        Long totalCount = getClinicNoticeCount(clinicId,empId);
        if(StringUtil.isBlank(totalCount)){
            return PageInfo.build();
        }
        List<ClinicNoticeVo> noticeList = getClinicNoticeList(clinicId,empId,pageNo,pageSize);
        return new PageInfo<>(totalCount,noticeList);
    }


    /**
     * 标记已读
     * @param batchDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void markDelete(BatchDTO batchDTO){
        List<Long> ids = batchDTO.getIds();
        if(CollectionUtils.isEmpty(ids)){
            throw new BusinessFailException("请先选择消息！");
        }
        //获取其中的未读消息数
        Long unreadCount = getClinicUnreadCount(batchDTO.getClinicId(),batchDTO.getUserId(),ids);
        //标记已读
        deleteNoticeRead(ids);
        //更新消息的未读数
        updateLastRead(batchDTO.getClinicId(),batchDTO.getUserId(), Math.toIntExact(unreadCount));
    }

    public void deleteNoticeRead(List<Long> noticeIdList) {
        ClinicNoticeExample example = new ClinicNoticeExample();
        ClinicNoticeExample.Criteria criteria = example.createCriteria();
        criteria.andNoticeIdIn(noticeIdList);
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        ClinicNotice clinicNotice = new ClinicNotice();
        clinicNotice.setIsDelete(YesOrNoEnum.YES.getValue());
        clinicNotice.setUpdateTime(new Date());
        clinicNoticeMapper.updateByExampleSelective(clinicNotice,example);
    }

    /**
     * 标记已读
     * @param batchDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void markRead(BatchDTO batchDTO){
        List<Long> ids = batchDTO.getIds();
        if(CollectionUtils.isEmpty(ids)){
            throw new BusinessFailException("请先选择消息！");
        }
        //获取其中的未读消息数
        Long unreadCount = getClinicUnreadCount(batchDTO.getClinicId(),batchDTO.getUserId(),ids);
        if(unreadCount <= CommonConstant.DEFAULT_0){
            return;
        }
        //标记已读
        updateNoticeRead(batchDTO.getUserId(),ids);
        //更新消息的未读数
        updateLastRead(batchDTO.getClinicId(),batchDTO.getUserId(), Math.toIntExact(unreadCount));
    }

    /**
     * 标记已读
     * @param batchDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void markAllRead(BatchDTO batchDTO){
        //获取其中的未读消息数
        Long unreadCount = getClinicUnreadCount(batchDTO.getClinicId(),batchDTO.getUserId(),null);
        if(unreadCount <= CommonConstant.DEFAULT_0){
            return;
        }
        //标记已读
        updateNoticeRead(batchDTO.getUserId(),null);
        //更新消息的未读数
        updateLastRead(batchDTO.getClinicId(),batchDTO.getUserId(), Math.toIntExact(unreadCount));
    }

    /**
     * 更新消息的未读数
     * @param empId
     * @param unreadCount
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateLastRead(Long clinicId,Long empId, Integer unreadCount) {
        if(unreadCount <= CommonConstant.DEFAULT_0){
            return;
        }
        ClinicNoticeLastRead clinicNoticeLastRead = geLastReadByEmpId(clinicId,empId);
        clinicNoticeLastRead.setLastReadTime(new Date());
        clinicNoticeLastRead.setUnreadNum(clinicNoticeLastRead.getUnreadNum() - unreadCount);
        if(clinicNoticeLastRead.getUnreadNum() < CommonConstant.DEFAULT_0){
            clinicNoticeLastRead.setUnreadNum(CommonConstant.DEFAULT_0);
        }
        clinicNoticeLastRead.setUpdateTime(new Date());
        clinicNoticeLastReadMapper.updateByPrimaryKeySelective(clinicNoticeLastRead);
    }

    /**
     * 标记已读
     * @param noticeIdList
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateNoticeRead(Long empId,List<Long> noticeIdList) {
        ClinicNoticeExample example = new ClinicNoticeExample();
        ClinicNoticeExample.Criteria criteria = example.createCriteria();
        if(!CollectionUtils.isEmpty(noticeIdList)){
            criteria.andNoticeIdIn(noticeIdList);
        }
        if(!StringUtil.isBlank(empId)){
            criteria.andEmpIdEqualTo(empId);
        }
        criteria.andIsReadEqualTo(YesOrNoEnum.NO.getValue());
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        ClinicNotice clinicNotice = new ClinicNotice();
        clinicNotice.setIsRead(YesOrNoEnum.YES.getValue());
        clinicNotice.setUpdateTime(new Date());
        clinicNoticeMapper.updateByExampleSelective(clinicNotice,example);
    }

    /**
     * 获取未读数
     * @param noticeIdList
     * @return
     */
    public Long getClinicUnreadCount(Long clinicId,Long empId,List<Long> noticeIdList) {
        ClinicNoticeExample example = new ClinicNoticeExample();
        ClinicNoticeExample.Criteria criteria = example.createCriteria();
        criteria.andClinicIdEqualTo(clinicId);
        criteria.andEmpIdEqualTo(empId);
        if(!CollectionUtils.isEmpty(noticeIdList)){
            criteria.andNoticeIdIn(noticeIdList);
        }
        criteria.andIsReadEqualTo(YesOrNoEnum.NO.getValue());
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        return clinicNoticeMapper.countByExample(example);
    }



    public Long getClinicNoticeCount(Long clinicId,Long empId) {
        ClinicNoticeExample example = new ClinicNoticeExample();
        ClinicNoticeExample.Criteria criteria = example.createCriteria();
        if (!StringUtil.isBlank(empId)) {
            criteria.andEmpIdEqualTo(empId);
        }
        criteria.andClinicIdEqualTo(clinicId);
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        return clinicNoticeMapper.countByExample(example);
    }

    public List<ClinicNoticeVo> getClinicNoticeList(Long clinicId,Long empId, Integer pageNo, Integer pageSize) {
        ClinicNoticeExample example = new ClinicNoticeExample();
        ClinicNoticeExample.Criteria criteria = example.createCriteria();
        if (!StringUtil.isBlank(empId)) {
            criteria.andEmpIdEqualTo(empId);
        }
        criteria.andClinicIdEqualTo(clinicId);
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        example.setOffset(PageUtils.getOffset(pageNo,pageSize));
        example.setLimit(pageSize);
        example.setOrderByClause("notice_time desc");
        List<ClinicNotice> noticeList = clinicNoticeMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(noticeList)){
            return null;
        }
        return noticeList.stream().map(notice -> {
            ClinicNoticeVo clinicNoticeVo = new ClinicNoticeVo();
            BeanUtils.copyProperties(notice, clinicNoticeVo);
            return clinicNoticeVo;
        }).collect(Collectors.toList());
    }


    /**
     * 分页查询诊所消息
     * @param noticeName 消息标题（可选条件）
     * @param pageNo 页码
     * @param pageSize 每页条数
     * @return 分页结果
     */
    public PageInfo<ClinicNotice> getClinicNoticeListByCondition(String noticeName, Integer pageNo, Integer pageSize) {
        ClinicNoticeExample example = new ClinicNoticeExample();
        ClinicNoticeExample.Criteria criteria = example.createCriteria();
        if (StringUtil.isNotBlank(noticeName)) {
            criteria.andNoticeNameLike("%" + noticeName + "%");
        }
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        Long totalCount = clinicNoticeMapper.countByExample(example);
        if (totalCount == null || totalCount == 0) {
            return PageInfo.build();
        }
        example.setOffset(PageUtils.getOffset(pageNo, pageSize));
        example.setLimit(pageSize);
        example.setOrderByClause("create_time desc");
        List<ClinicNotice> list = clinicNoticeMapper.selectByExample(example);
        return new PageInfo<>(totalCount, list);
    }

    /**
     * 添加诊所消息
     * @param clinicNotice 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void addNotice(ClinicNotice clinicNotice) {
        validateClinicNotice(clinicNotice);
        if(StringUtil.isBlank(clinicNotice.getNoticeType())){
            clinicNotice.setNoticeType(NoticeTypeEnum.UNICAST.getValue());
        }
        clinicNotice.setNoticeTime(new Date());
        clinicNotice.setIsRead(YesOrNoEnum.NO.getValue());
        clinicNotice.setIsDelete(YesOrNoEnum.NO.getValue());
        clinicNotice.setCreateTime(new Date());
        clinicNoticeMapper.insertSelective(clinicNotice);
        updateLastMsg(clinicNotice.getClinicId(),clinicNotice.getEmpId(),clinicNotice.getNoticeName());
    }


    /**
     * 更新员工最新消息
     * @param empId
     * @param lastMsg
     */
    public void updateLastMsg(Long clinicId,Long empId, String lastMsg) {
        ClinicNoticeLastRead clinicNoticeLastRead = geLastReadByEmpId(clinicId,empId);
        if(clinicNoticeLastRead != null){
            clinicNoticeLastRead.setLastMsg(StringUtil.subString50(lastMsg));
            clinicNoticeLastRead.setLastMsgTime(new Date());
            clinicNoticeLastRead.setUnreadNum(clinicNoticeLastRead.getUnreadNum() + CommonConstant.DEFAULT_1);
            clinicNoticeLastRead.setUpdateTime(new Date());
            clinicNoticeLastReadMapper.updateByPrimaryKeySelective(clinicNoticeLastRead);
        }else {
            clinicNoticeLastRead = new ClinicNoticeLastRead();
            clinicNoticeLastRead.setEmpId(empId);
            clinicNoticeLastRead.setLastMsg(StringUtil.subString50(lastMsg));
            clinicNoticeLastRead.setLastMsgTime(new Date());
            clinicNoticeLastRead.setUnreadNum(CommonConstant.DEFAULT_1);
            clinicNoticeLastRead.setClinicId(clinicId);
            clinicNoticeLastRead.setCreateTime(new Date());
            clinicNoticeLastReadMapper.insertSelective(clinicNoticeLastRead);
        }
    }

    public ClinicNoticeLastRead geLastReadByEmpId(Long clinicId,Long empId) {
        List<ClinicNoticeLastRead> lastReadList = geLastReadListByEmpId(clinicId,empId);
        return CollectionUtils.isEmpty(lastReadList) ? null : lastReadList.get(0);
    }

    public List<ClinicNoticeLastRead> geLastReadListByEmpId(Long clinicId,Long empId) {
        ClinicNoticeLastReadExample example = new ClinicNoticeLastReadExample();
        ClinicNoticeLastReadExample.Criteria criteria = example.createCriteria();
        criteria.andEmpIdEqualTo(empId);
        criteria.andClinicIdEqualTo(clinicId);
        return clinicNoticeLastReadMapper.selectByExample(example);
    }

    /**
     * 校验诊所消息参数
     * @param clinicNotice 实体
     */
    public void validateClinicNotice(ClinicNotice clinicNotice) {
        if (clinicNotice == null) {
            throw new BusinessFailException("诊所消息不能为空");
        }
        if (!StringUtils.hasText(clinicNotice.getNoticeName())) {
            throw new BusinessFailException("消息标题不能为空");
        }
        if (!StringUtils.hasText(clinicNotice.getNoticeContent())) {
            throw new BusinessFailException("消息内容不能为空");
        }
    }

    /**
     * 根据ID查询诊所消息
     * @param noticeId 主键
     * @return 诊所消息记录
     */
    public ClinicNotice getClinicNoticeById(Long noticeId) {
        if (StringUtil.isBlank(noticeId)) {
            return null;
        }
        ClinicNotice clinicNotice = clinicNoticeMapper.selectByPrimaryKey(noticeId);
        if(clinicNotice == null || YesOrNoEnum.YES.getValue().equals(clinicNotice.getIsDelete())){
            return null;
        }
        return clinicNotice;
    }

    /**
     * 修改诊所消息
     * @param clinicNotice 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateNotice(ClinicNotice clinicNotice) {
        validateClinicNotice(clinicNotice);
        ClinicNotice dbNotice = getClinicNoticeById(clinicNotice.getNoticeId());
        if (dbNotice == null) {
            throw new BusinessFailException("消息不存在");
        }
        clinicNotice.setUpdateTime(new Date());
        clinicNoticeMapper.updateByPrimaryKeySelective(clinicNotice);
    }

    /**
     * 删除诊所消息（逻辑删除）
     * @param clinicNotice 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteNotice(ClinicNotice clinicNotice) {
        ClinicNotice dbNotice = getClinicNoticeById(clinicNotice.getNoticeId());
        if (dbNotice == null) {
            throw new BusinessFailException("消息不存在");
        }
        dbNotice.setIsDelete(YesOrNoEnum.YES.getValue());
        dbNotice.setUpdateTime(new Date());
        clinicNoticeMapper.updateByPrimaryKeySelective(dbNotice);
    }


    /**
     * 分页查询消息阅读标记
     * @param empId 员工ID
     * @param pageNo 页码
     * @param pageSize 每页条数
     * @return 分页结果
     */
    public PageInfo<ClinicNoticeLastRead> getClinicNoticeLastReadListByCondition(Long empId, Integer pageNo, Integer pageSize) {
        ClinicNoticeLastReadExample example = new ClinicNoticeLastReadExample();
        ClinicNoticeLastReadExample.Criteria criteria = example.createCriteria();
        if (empId != null) {
            criteria.andEmpIdEqualTo(empId);
        }
        Long totalCount = clinicNoticeLastReadMapper.countByExample(example);
        if (totalCount == null || totalCount == 0) {
            return PageInfo.build();
        }
        example.setOffset(PageUtils.getOffset(pageNo, pageSize));
        example.setLimit(pageSize);
        example.setOrderByClause("create_time desc");
        List<ClinicNoticeLastRead> list = clinicNoticeLastReadMapper.selectByExample(example);
        return new PageInfo<>(totalCount, list);
    }

    /**
     * 添加消息阅读标记
     * @param clinicNoticeLastRead 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void addNoticeLastRead(ClinicNoticeLastRead clinicNoticeLastRead) {
        validateClinicNoticeLastRead(clinicNoticeLastRead);
        clinicNoticeLastRead.setCreateTime(new Date());
        clinicNoticeLastReadMapper.insertSelective(clinicNoticeLastRead);
    }

    /**
     * 校验消息阅读标记参数
     * @param clinicNoticeLastRead 实体
     */
    public void validateClinicNoticeLastRead(ClinicNoticeLastRead clinicNoticeLastRead) {
        if (clinicNoticeLastRead == null) {
            throw new BusinessFailException("消息阅读标记不能为空");
        }
    }

    /**
     * 根据ID查询消息阅读标记
     * @param readId 主键
     * @return 消息阅读标记记录
     */
    public ClinicNoticeLastRead getClinicNoticeLastReadById(Long readId) {
        if (readId == null) {
            return null;
        }
        return clinicNoticeLastReadMapper.selectByPrimaryKey(readId);
    }

    /**
     * 修改消息阅读标记
     * @param clinicNoticeLastRead 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateNoticeLastRead(ClinicNoticeLastRead clinicNoticeLastRead) {
        validateClinicNoticeLastRead(clinicNoticeLastRead);
        ClinicNoticeLastRead dbEntity = getClinicNoticeLastReadById(clinicNoticeLastRead.getReadId());
        if (dbEntity == null) {
            throw new BusinessFailException("记录不存在");
        }
        clinicNoticeLastRead.setUpdateTime(new Date());
        clinicNoticeLastReadMapper.updateByPrimaryKeySelective(clinicNoticeLastRead);
    }
}
